<template>
  <div id="map-container">
    <el-button type="text" size="large" class="back" @click="back" v-if="deepTree.length > 1">返回</el-button>
    <div class="echarts">
      <div id="map"></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
import * as echarts from 'echarts'
import { getChinaJson, getProvinceJson, getCityJson, getDistrictJson } from "@/api/map/map";
import { mapOption } from '@/config/mapOption'
import { useResize } from '@/utils/resize'

// Props
interface Props {
  areaCode?: string
  areaLevel?: string | number
  areaName?: string
  mapNameList?: string[]
  mapCodeList?: string[]
  areaStatistic?: any[]
}

const props = withDefaults(defineProps<Props>(), {
  areaCode: '000000000000',
  areaLevel: 0,
  areaName: 'china',
  mapNameList: () => [],
  mapCodeList: () => [],
  areaStatistic: () => []
})

// Emits
const emit = defineEmits<{
  'update:areaCode': [value: string]
  'update:areaLevel': [value: number]
  'update:areaName': [value: string]
  'update:mapNameList': [value: string[]]
  'update:mapCodeList': [value: string[]]
}>()

// Reactive data
const chart = ref<echarts.ECharts | null>(null) // 实例化echarts
const mapDataList = ref<any[]>([]) // 当前地图上的地区
const option = ref({...mapOption.basicOption}) // map的相关配置
const deepTree = ref<any[]>([])// 点击地图时push，点返回时pop
const areaStatisticMapValue = ref<Record<string, number>>({}) // 地图数据value, 只是amounts
const areaStatisticMapData = ref<Record<string, any>>({}) // 地图数据data,包含所有数据
const tooltipAutoplay = ref<NodeJS.Timeout | null>(null) // 提示框自动播放
const tooltipAutoplayIndex = ref(0) // 提示框自动播放index

const areaLevelMap = {
  'country': 0,
  'china': 0,
  'province': 1,
  'city': 2,
  'district': 3,
}

// Resize composable
const { resize } = useResize(chart)

// 初次加载绘制地图
const initEcharts = () => {
  //地图容器
  chart.value = echarts.init(document.getElementById('map') as HTMLElement);
  if (props.areaLevel === 0) {
    requestGetChinaJson();
  } else if (props.areaLevel === 1) {
    requestGetProvinceJSON({name: props.areaName, level: 'province', adcode: props.areaCode.substr(0, 6)})
  } else if (props.areaLevel === 2) {
    requestGetCityJSON({name: props.areaName, level: 'city', adcode: props.areaCode.substr(0, 6)})
  } else if (props.areaLevel === 3) {
    requestGetDistrictJSON({name: props.areaName, level: 'district', adcode: props.areaCode.substr(0, 6)})
  }
}

// 地图点击
const echartsMapClick = (params: any) => {
  emit('update:areaCode', params.data.adcode + '000000')
  emit('update:areaName', params.data.name)
  emit('update:areaLevel', areaLevelMap[params.data.level])
  if (params.data.level === 'province') {
    requestGetProvinceJSON(params.data);
  } else if (params.data.level === 'city') {
    requestGetCityJSON(params.data)
  } else if (params.data.level === 'district' && mapDataList.value.length > 1) {
    requestGetDistrictJSON(params.data)
  }
}

//绘制全国地图areaStatistic
const requestGetChinaJson = async () => {
  try {
    const res = await getChinaJson()
    emit('update:areaLevel', 0)
    setJsonData(res)
  } catch (error) {
    console.error('Error loading China JSON:', error)
  }
}

// 加载省级地图
const requestGetProvinceJSON = async (params: any) => {
  try {
    const res = await getProvinceJson(params.adcode, params)
    emit('update:areaLevel', 1)
    setJsonData(res, params)
  } catch (error) {
    console.error('Error loading province JSON:', error)
  }
}

// 加载市级地图
const requestGetCityJSON = async (params: any) => {
  try {
    const res = await getCityJson(params.adcode, params)
    emit('update:areaLevel', 2)
    setJsonData(res, params)
  } catch (error) {
    console.error('Error loading city JSON:', error)
  }
}

// 加载县级地图
const requestGetDistrictJSON = async (params: any) => {
  try {
    const res = await getDistrictJson(params.adcode, params)
    emit('update:areaLevel', 3)
    setJsonData(res, params)
  } catch (error) {
    console.error('Error loading district JSON:', error)
  }
}

// 设置数据
const setJsonData = (res: any, params?: any) => {
  const mapDataListTemp: any[] = [];
  const mapNameListTemp: string[] = [];
  const mapCodeListTemp: string[] = [];
  
  for (let i = 0; i < res.features.length; i++) {
    const obj = {
      ...res.features[i].properties,
      value: _mathRandom1000(),
      valueData: _mathRandom1000(),
    };
    mapDataListTemp.unshift(obj)
    mapNameListTemp.unshift(res.features[i].properties.name)
    mapCodeListTemp.unshift(res.features[i].properties.adcode + '000000')
  }
  
  mapDataList.value = mapDataListTemp;
  emit('update:mapNameList', mapNameListTemp)
  emit('update:mapCodeList', mapCodeListTemp)
  setMapData(res, params)
}

// 设置地图信息
const setMapData = (res: any, params?: any) => {
  if (props.areaName === 'china') {
    deepTree.value.push({
      mapDataList: mapDataList.value,
      params: {name: 'china', level: 'country', adcode: '100000'}
    });
    //注册地图
    echarts.registerMap('china', res);
    //绘制地图
    renderMap('china', mapDataList.value);
  } else {
    deepTree.value.push({mapDataList: mapDataList.value, params: params});
    echarts.registerMap(params.name, res);
    renderMap(params.name, mapDataList.value);
  }
}

// 渲染地图
const renderMap = (map: string, data: any[]) => {
  const mapDataList = data.map(item => {
    return {
      name: item.name,
      value: item.value
    }
  }).sort((a, b) => b.value - a.value);
  
  const pointData = []
  for (let i = 0; i < data.length; i++) {
    if (data[i].value != 0) {
      pointData.push({
        ...data[i],
        value: [data[i].center[0], data[i].center[1], data[i].value],
      })
    }
  }
  
  // 设置左下角数量范围值
  option.value.visualMap.min = mapDataList.length > 1 ? mapDataList[mapDataList.length - 2].value : 0
  option.value.visualMap.max = mapDataList.length > 0 ? mapDataList[0].value : 0
  // 设置左上角当前位置
  option.value.title[0].text = map === 'china' ? '全国' : map
  option.value.geo = {
    show: false,
    map: map,
    zoom: 1.2, //当前视角的缩放比例
    roam: true, //是否开启平游或缩放
    center: undefined,
  }
  option.value.series = [
    {
      name: map,
      mapType: map,
      zoom: 1, //当前视角的缩放比例
      roam: false, //是否开启平游或缩放
      center: undefined,
      scaleLimit: { //滚轮缩放的极限控制
        min: .5,
        max: 10
      },
      ...mapOption.seriesOption,
      data: data
    },
    {
      name: '散点',//series名称
      type: 'effectScatter',//散点类型
      coordinateSystem: 'geo',// series坐标系类型
      rippleEffect: {
        brushType: 'fill'
      },
      normal: {
        show: true,
        // 提示内容
        formatter: (params: any) => {
          return params.name;
        },
        position: 'top', // 提示方向
        color: '#fff'
      },
      emphasis: {
        show: true // 点
      },
      itemStyle: {
        normal: {
          color: '#F4E925',
          shadowBlur: 10,
          shadowColor: '#000'
        }
      },
      // symbol:'pin', // 散点样式'pin'（标注）、'arrow'（箭头）
      data: pointData,
      symbolSize: function (val: any[]) {
        // return val[2] / 100;
        if (val[2] === mapDataList[0].value) {
          return 10
        }
        return 6
      },
      showEffectOn: 'render', //加载完毕显示特效
    },
  ]
  
  //渲染地图
  if (chart.value) {
    chart.value.setOption(option.value, true)
    setTooltipAutoplay()
  }
}

// 地图鼠标移入事件
const echartsMapMouseover = () => {
  if (tooltipAutoplay.value) {
    clearInterval(tooltipAutoplay.value)
  }
}

// 地图鼠标移出事件
const echartsMapMouseout = () => {
  setTooltipAutoplay()
}

// 动态显示tooltip
const setTooltipAutoplay = () => {
  if (tooltipAutoplay.value) {
    clearInterval(tooltipAutoplay.value)
  }
  
  tooltipAutoplay.value = setInterval(() => {
    if (chart.value) {
      chart.value.dispatchAction({
        type: 'showTip',
        seriesIndex: 0,
        dataIndex: tooltipAutoplayIndex.value
      })
      tooltipAutoplayIndex.value++
      if (tooltipAutoplayIndex.value >= mapDataList.value.length) {
        tooltipAutoplayIndex.value = 0;
      }
    }
  }, 6666)
}

// 返回
const back = () => {
  if (deepTree.value.length > 1) {
    deepTree.value.pop();
    mapDataList.value = deepTree.value[deepTree.value.length - 1].mapDataList;
    const areaName = deepTree.value[deepTree.value.length - 1].params.name;
    const areaCode = deepTree.value[deepTree.value.length - 1].params.adcode;
    const areaLevel = deepTree.value[deepTree.value.length - 1].params.level;
    const mapNameList = mapDataList.value.map(item => item.name)
    const mapCodeList = mapDataList.value.map(item => item.adcode + '000000')
    
    emit('update:areaCode', (areaCode === '100000' ? '000000' : areaCode) + '000000')
    emit('update:areaName', areaName)
    emit('update:areaLevel', areaLevelMap[areaLevel])
    emit('update:mapNameList', mapNameList)
    emit('update:mapCodeList', mapCodeList)
    renderMap(areaName, mapDataList.value);
  }
}

// Helper function
const _mathRandom1000 = () => {
  return Math.floor(Math.random() * 1000)
}

// Watchers
watch(() => props.areaStatistic, (val) => {
  const objValue: Record<string, number> = {}
  const objData: Record<string, any> = {}
  
  for (let i = 0; i < val.length; i++) {
    objValue[val[i]['areaCode'].substr(0, 6)] = val[i].amounts * 1
    objData[val[i]['areaCode'].substr(0, 6)] = val[i]
  }
  
  areaStatisticMapValue.value = objValue
  areaStatisticMapData.value = objData
  initEcharts()
}, { deep: true })

// Lifecycle
onMounted(() => {
  nextTick(() => {
    initEcharts();
    if (chart.value) {
      chart.value.on('click', echartsMapClick);
      chart.value.on('mouseover', echartsMapMouseover);
      chart.value.on('mouseout', echartsMapMouseout);
    }
  });
})

onBeforeUnmount(() => {
  if (tooltipAutoplay.value) {
    clearInterval(tooltipAutoplay.value)
  }
  if (chart.value) {
    chart.value.dispose()
    chart.value = null
  }
})
</script>

<style lang="scss" scoped>
#map-container {
  height: 100%;
  width: 100%;
  position: relative;
  display: flex;
  flex-direction: column;

  .echarts {
    flex: 1;
    width: 100%;
    height: 100%;
    min-height: 600px;

    #map {
      width: 100%;
      height: 100%;
    }
  }

  .back {
    position: absolute;
    top: 20px;
    left: 20px;
    z-index: 9;
    font-weight: bolder;
    font-size: 16px;
    padding: 8px 16px;
    background: rgba(0, 0, 0, 0.7);
    border: 1px solid rgba(79, 149, 255, 0.5);
    border-radius: 4px;
    color: #4F95FF;
    
    &:hover {
      background: rgba(79, 149, 255, 0.2);
      border-color: rgba(79, 149, 255, 0.8);
    }
  }
}

</style>

